﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Runtime.Serialization;
using System.ComponentModel;

namespace WebPALTT.Lib
{
    // This file defines the abstract class ActionItem as well as each of the classes that inherits from ActionItem.
    // Each of the classes that inherit from ActionItem represents a seperate type of action item in the scenario.
    // The file also contains a collection class for ActionItem objects 
    // and the ActionResults definition which is used by ActionItem to store the results of each action.

    /// <summary>
    /// An abstract class that is used as the generic form of all action item types. 
    /// </summary>
    [Serializable]
    public abstract class ActionItem : ISerializable
    {
        Guid mKey;
        String mName;
        ActionResults mResults;
        ActionItem mParent = null;
        int mIndex = -1;

        /// <summary>
        /// Gets the key of the action.
        /// </summary>
        [ReadOnlyAttribute(true), BrowsableAttribute(false)]
        public virtual Guid Key { get { return mKey; } }
        /// <summary>
        /// Gets or sets the name of the action.
        /// </summary>
        [CategoryAttribute("Action Properties")]
        public virtual String Name { get { return mName; } set { mName = value; } }
        /// <summary>
        /// Gets the parent action on the current action.
        /// </summary>
        [ReadOnlyAttribute(true), BrowsableAttribute(false)]        
        public virtual ActionItem Parent { get { return mParent; } }
        /// <summary>
        /// Gets the index of this action in its parent.
        /// </summary>
        [ReadOnlyAttribute(true), BrowsableAttribute(false)]
        public virtual int Index { get { return mIndex; } }
        /// <summary>
        /// Gets the ActionType. This is an abstract property that is implemented seperately in each action item. 
        /// This property is now only used to differentiate between ScriptItems and other actions.
        /// </summary>
        [CategoryAttribute("Action Properties"), ReadOnlyAttribute(true)]
        public abstract ActionType ActionType { get; }
        /// <summary>
        /// Gets the type of the Action.
        /// </summary>
        [CategoryAttribute("Action Properties"), ReadOnlyAttribute(true)]
        public abstract String CustomType { get; }
        [CategoryAttribute("Action Properties"), ReadOnlyAttribute(true)]
        public abstract System.Drawing.Image Icon { get; }
        /// <summary>
        /// Indicates if this action has any children.
        /// </summary>
        [BrowsableAttribute(false)]
        public abstract bool HasChildren { get; }
        /// <summary>
        /// Indicates if child actions can be added to this action.
        /// </summary>
        [BrowsableAttribute(false)]
        public abstract bool CanAddChildren { get; }
        /// <summary>
        /// Returns an array containing the headers that are added to the Data object in the results.
        /// </summary>
        [BrowsableAttribute(false)]
        public abstract string[] DataHeaders { get; }
        /// <summary>
        /// Gets a collection containing the child items of this action.
        /// </summary>
        [BrowsableAttribute(false)]
        public abstract string[] DataHeaders_Save { get; }
        [BrowsableAttribute(false)]
        public abstract ExecutionStatus ExecutionStatus { get; }

        protected ExecutionStatus mExecutionStatus = ExecutionStatus.NotRun;

        public ActionItem()
        { this.mKey = Guid.NewGuid(); }

        public ActionItem(String name) : this()
        { mName = name; }

        public ActionItem(SerializationInfo info, StreamingContext ctxt)
        {
            mName = (string)info.GetValue("Name", typeof(string));
            mResults = (ActionResults)info.GetValue("Results", typeof(ActionResults));
            try
            {
                mKey = (Guid)info.GetValue("Key", typeof(Guid));
            }
            catch (SerializationException) { mKey = Guid.NewGuid(); }
        }

        public virtual void GetObjectData(SerializationInfo info, StreamingContext ctxt)
        {
            info.AddValue("Name", mName);
            info.AddValue("Results", mResults);
            info.AddValue("Key", mKey);
        }

        public virtual void SetParent(ActionItem parent, int index = 0)
        {
            mParent = parent;
            if (index < 0)
                throw new IndexOutOfRangeException("Index must be greater than or equal to zero.");
            mIndex = index;
        }

        public virtual void SetIndex(int index)
        {
            if (index < 0)
                throw new IndexOutOfRangeException("Index must be greater than or equal to zero.");
            mIndex = index;
        }
        /// <summary>
        /// Returns the first child action with the key.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public abstract ActionItem FindChild(Guid key);
        /// <summary>
        /// Returns an array of the child actions with the key.
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public abstract ActionItem[] FindChildren(Guid key);
        /// <summary>
        /// Gets a collection of Child actions.
        /// </summary>
        [BrowsableAttribute(false)]
        public abstract ActionItemCollection Children { get; }        
        
        public abstract string[] Validate();

        public abstract Dictionary<string, object> Execute(Scenario scenario, ScenarioResults resultScene, Type scriptType, object scriptObj);
    }

    /*
     * Type: ActionType
     * 
     * An enum that defines the different types of actions available.
     * 
     * Values:
     * + Script
     * + Action
     */
    public enum ActionType { Script, Action }
    public enum ExecutionStatus { Complete, NotRun, Unknown, RunChildren}
}